#include "widget.h"
#include "ui_widget.h"
#include "widget.h"
#include <QColor>
#include <QDebug>
#include <QPushButton>
#include <QRect>
#include <QPoint>
#include <QDialog>
#include <stdlib.h>
const QSize g_qsize(620, 690);
const int32_t g_gap = 20;
const int32_t g_frameBlod = 5;
const int32_t g_frameGap = 5;
const int32_t g_defaultBoradLength = 70;

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
    ui->setupUi(this);
    resize(g_qsize);
    // setFixedSize(600,800);
    // m_rect = geometry();
    setMinimumSize(g_qsize);
    m_rect.setSize(g_qsize);
    border_length = (m_rect.x() - g_gap * 2 - g_frameBlod - g_frameGap) / 8;
    m_gapx = g_gap;
    m_gapy = g_gap;

    init();
}

Widget::~Widget() { delete ui; }

void Widget::init()
{
    m_chooseChess = -1;
    isRedTrun = true;

    int i = 0;
    chessInfos[i].x = i;
    chessInfos[i].y = 0;
    chessInfos[i++].type = car;

    chessInfos[i].x = i;
    chessInfos[i].y = 0;
    chessInfos[i++].type = horse;

    chessInfos[i].x = i;
    chessInfos[i].y = 0;
    chessInfos[i++].type = elephant;

    chessInfos[i].x = i;
    chessInfos[i].y = 0;
    chessInfos[i++].type = housecarl;

    chessInfos[i].x = i;
    chessInfos[i].y = 0;
    chessInfos[i].type = general;

    for (int j = 5; j < 9; j++) {
        chessInfos[j].x = j;
        chessInfos[j].y = 0;
        chessInfos[j].type = chessInfos[--i].type;
    }

    chessInfos[9].x = 1;
    chessInfos[9].y = 2;
    chessInfos[9].type = cannon;

    chessInfos[10].x = 7;
    chessInfos[10].y = 2;
    chessInfos[10].type = cannon;
    for (int j = 11; j < 16; ++j) {
        chessInfos[j].type = soldier;
        chessInfos[j].x = (j -  11)*2;
        chessInfos[j].y = 3;
    }
    // 按照中心对称（4,4.5）旋转赋值
    for (int j = 16, k = 15; j < allChess, k >=0; ++j, --k) {
        chessInfos[j].x = 8 - chessInfos[k].x;
        chessInfos[j].y = 9 - chessInfos[k].y;
        chessInfos[j].red = true;
        chessInfos[j].type = chessInfos[k].type;
    }

    for (int i = 0; i < allChess; i++) {
        chessInfos[i].name = chessName[chessInfos[i].type];
        chessInfos[i].dead = false;
        chessInfos[i].choosed = false;
        //qDebug()<<i<<":(x,y):"<<chessInfos[i].x<<"  "<<chessInfos[i].y;
    }
}

void Widget::getSuitableRect() {
    QRect rect = this->geometry();
    int32_t wide_t = (rect.width() - 2 * (g_gap + g_frameBlod + g_frameGap)) / 8;
    int32_t height_t =
            (rect.height() - 2 * (g_gap + g_frameBlod + g_frameGap)) / 9;
    //qDebug() << " rect: " << rect;
    //qDebug() << " wide_t: " << wide_t;
    wide_t = wide_t > height_t ? height_t : wide_t;
    m_gapx = (rect.width() - wide_t * 8) / 2 - g_frameBlod - g_frameGap;
    m_gapy = (rect.height() - wide_t * 9) / 2 - g_frameBlod - g_frameGap;

    scale = (double)wide_t / g_defaultBoradLength;
    border_length = wide_t;
    m_rect = rect;
}

void Widget::drawChessFrom() {
    QPainter painter(this);
    QPen pen;
    pen.setColor(Qt::black);
    pen.setWidth(0);
    painter.setPen(pen);

    int x = m_gapx + g_frameBlod + g_frameGap;
    int y = m_gapy + g_frameBlod + g_frameGap;
    int x1, x2, y1, y2;
    for (int i = 1; i < 8; ++i) {
        x1 = x + border_length * i;
        y1 = y;
        x2 = x1;
        y2 = y + border_length * 4;
        painter.drawLine(QLine(x1, y1, x2, y2));
        y1 = y + border_length * 5;
        y2 = y + border_length * 9;
        painter.drawLine(QLine(x1, y1, x2, y2));
    }

    for (int i = 1; i < 9; ++i) {
        x1 = x;
        y1 = y + border_length * i;
        x2 = x + border_length * 8;
        y2 = y1;
        painter.drawLine(QLine(x1, y1, x2, y2));
    }
}

void Widget::drawChessBoard() {
    QPainter painter(this);
    QPen pen;
    pen.setColor(Qt::black);
    pen.setWidth(g_frameBlod);
    painter.setPen(pen);
    QRect dr(m_gapx, m_gapy, m_rect.width() - m_gapx * 2,
             m_rect.height() - m_gapy * 2);
    painter.drawRect(dr);

    int x = m_gapx + g_frameBlod + g_frameGap;
    int y = m_gapy + g_frameBlod + g_frameGap;
    int wide_t = m_rect.width() - x * 2;
    int height_t = m_rect.height() - y * 2;
    QRect dr_1(x, y, wide_t, height_t);
    pen.setWidth(0);
    painter.setPen(pen);
    painter.drawRect(dr_1);
}

void Widget::drawChessKingArea() {
    QPainter painter(this);
    QPen pen;
    pen.setColor(Qt::black);
    pen.setWidth(0);
    painter.setPen(pen);

    int x1 = m_gapx + g_frameBlod + g_frameGap + border_length * 3;
    int y1 = m_gapy + g_frameBlod + g_frameGap;
    int x2 = x1 + border_length * 2;
    int y2 = y1 + border_length * 2;
    painter.drawLine(QLine(x1, y1, x2, y2));
    painter.drawLine(QLine(x1, y2, x2, y1));

    y1 += border_length * 7;
    y2 += border_length * 7;
    painter.drawLine(QLine(x1, y1, x2, y2));
    painter.drawLine(QLine(x1, y2, x2, y1));
}

void Widget::drawChessSoldiersArea() {}

void Widget::drawChesses() {
    QPainter painter(this);
    QPen pen;
    QFont qf("宋体", border_length / 2, QFont::Bold, true);
    painter.setFont(qf);
    pen.setColor(Qt::black);
    pen.setWidth(0);
    painter.setPen(pen);

    for (int i = 0; i < allChess; ++i) {
        if(chessInfos[i].dead){
            if(chessInfos[i].type == general)
            {
                init();
                update();
                return;
            }
            continue;
        }
        if (i > 15) {
            pen.setColor(Qt::red);
            painter.setPen(pen);
        }
        int x = chessInfos[i].x * border_length- border_length/2+m_gapx+ g_frameBlod + g_frameGap;
        int y = chessInfos[i].y * border_length -border_length / 2+m_gapy+ g_frameBlod + g_frameGap;
        QRect qr(x,y , border_length, border_length);
        painter.drawArc(qr, 0, 360 * 16);
        painter.drawText(qr, Qt::AlignCenter,chessInfos[i].name);
        if (chessInfos[i].choosed){
            painter.drawRect(qr);
        }
    }
}
void Widget::getXY(const QPoint& qp,int&x,int&y)
{
    // 求余取整
    x = (qp.x()-m_gapx-g_frameBlod - g_frameGap+border_length/2)/border_length;
    y = (qp.y()-m_gapy-g_frameBlod - g_frameGap+border_length/2)/border_length;
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    int x,y;
    bool chooseChess = false;
    QPoint qp=event->pos();
    getXY(qp,x,y);
    for(int i = 0; i < allChess; ++i) {
        if ((isRedTrun && i < 16) || (!isRedTrun && i > 15)) {
            continue;
        }
        if(chessInfos[i].x == x && chessInfos[i].y == y && chessInfos[i].dead == false) {
            chessInfos[i].choosed = true;
            chooseChess = true;
            m_chooseChess=i;
        } else {
            chessInfos[i].choosed = false;
        }
    }
    if (!chooseChess && m_chooseChess >= 0){
        // 按照规则走棋
        if(!GoChesses(chessInfos[m_chooseChess], x,y)){
            return;
        }
        // 检查是否是吃棋
        for (int i = 0; i < allChess; i++){
            if (chessInfos[i].x == x && chessInfos[i].y == y) {
                chessInfos[i].dead = true;
            }
        }
        chessInfos[m_chooseChess].x = x;
        chessInfos[m_chooseChess].y = y;
        // 走棋ok则设置false
        chessInfos[m_chooseChess].choosed = false;
        isRedTrun = !isRedTrun;
        m_chooseChess = -1;
    }

    update();
}

int Widget::GetFoot(chessInfo chess,int dstx,int dsty)
{
    int x = (chess.x+dstx)/2;
    int y = (chess.y+dsty)/2;
    return  CalSumXY(x,y,dstx,dsty);
}

bool Widget::GoChesses(chessInfo chess,int dstx,int dsty)
{
    bool flag = false;
    switch (chess.type) {
    case soldier :
        flag = GoSoldier(chess,dstx,dsty);
        break;
    case cannon:
        flag = GoCannon(chess,dstx,dsty);
        break;
    case car:
        flag = GoCar(chess,dstx,dsty);
        break;
    case horse:
        flag = GoHorse(chess,dstx,dsty);
        break;
    case elephant:
        flag = GoElephant(chess,dstx,dsty);
        break;
    case housecarl:
        flag = GoHousecarl(chess,dstx,dsty);
        break;
    case general:
        return GoGeneral(chess,dstx,dsty);
        //break;
    default:
        return false;
    }
    if (flag)
        return CheckKing(chess,dstx,dsty);
    return false;
}

int Widget::InOneLine(int x1,int y1,int x2,int y2){
    int oneLine = 0;
    if (x1 == x2 && y1 != y2) {
        oneLine = 1;
    }

    if (x1 != x2 && y1 == y2)
        oneLine = 2;
    return oneLine ;
}

bool Widget::GoCannon(chessInfo chess, int dstx, int dsty)
{
    m_type = unkonw;
    // 判断是否在一条直线上
    int oneLine = InOneLine(chess.x,chess.y,dstx,dsty);
    if (oneLine == 0){
        return false;
    }

    // 查询行走棋和目标点之间有几个棋子
    int chessNum = 0;
    for (int j=0;j < allChess&&chessNum<2;++j) {
        // 筛除自己或被吃掉的棋子
        if(chessInfos[j] == chess || chessInfos[j].dead) {
            continue;
        }
        float mid = (1.0*chess.y-chessInfos[j].y)/(chess.y-dsty);
        if(oneLine == 1){
            if (chessInfos[j].x == chess.x&&mid<1&&mid>0){
                m_type=chessInfos[j].type;
                chessNum++;
            }
        }
        mid = (1.0*chess.x-chessInfos[j].x)/(chess.x-dstx);
        if(oneLine == 2){
            if (chessInfos[j].y == chess.y&&mid<1&&mid>0){
                m_type=chessInfos[j].type;
                chessNum++;
            }
        }
    }

    //目标点是否是棋子,
    bool isChess = false;
    for (int i = 0; i < allChess && !isChess; ++i) {
        // 筛除己方
        if (chessInfos[i].red == chess.red||chessInfos[i] == chess)
        {
            continue;
        }

        if(chessInfos[i].x == dstx && chessInfos[i].y == dsty && !chessInfos[i].dead) {
            isChess = true;
        }
    }

    // 中间隔了大于1个棋子，无法移动
    if (chessNum > 1)
    {
        return false;
    }

    // 选中对方棋子且中间隔了一个棋子
    if (chessNum == 1 )  {
        return isChess;
    }

    // 返回目标点非棋子时能走棋
    return !isChess;
}

bool Widget::GoCar(chessInfo chess, int dstx, int dsty)
{
    // 判断是否在一条直线上
    int oneLine = InOneLine(chess.x,chess.y,dstx,dsty);
    if (oneLine == 0){
        return false;
    }

    // 查询行走棋和目标点之间有几个棋子
    int chessNum = 0;
    for (int j=0;j < allChess&&chessNum<2;++j) {
        // 筛除自己或被吃掉的棋子
        if(chessInfos[j] == chess || chessInfos[j].dead) {
            continue;
        }
        float mid = (1.0*chess.y-chessInfos[j].y)/(chess.y-dsty);
        if(oneLine == 1){
            if (chessInfos[j].x == chess.x&&mid<1&&mid>0){
                chessNum++;
            }
        }
        mid = (1.0*chess.x-chessInfos[j].x)/(chess.x-dstx);
        if(oneLine == 2){
            if (chessInfos[j].y == chess.y&&mid<1&&mid>0){
                chessNum++;
            }
        }
    }

    return  chessNum == 0;
}

bool Widget::GoHorse(chessInfo chess, int dstx, int dsty)
{
    int sumTmp = CalSumXY(chess,dstx,dsty);
    if(sumTmp!= 12 && sumTmp != 21)
        return false;
    int midx = (chess.x+dstx) / 2;
    int midy = (chess.y+dsty) / 2;
    for (int j=0;j < allChess;++j) {
        if (!chessInfos[j].dead&&chessInfos[j].x == midx && chessInfos[j].y == midy){
            return false;
        }
    }

    return true;
}

int Widget::CalSumXY(int x,int y,int dstx,int dsty)
{
    return abs(x-dstx)+abs(y-dsty)*10;
}

int Widget::CalSumXY(const chessInfo& chess,int dstx,int dsty)
{
    return abs(chess.x-dstx)+abs(chess.y-dsty)*10;
}
bool Widget::GoSoldier(chessInfo chess, int dstx, int dsty)
{
    // 未过河只能前进一步，过河能向前左右移动一步
    bool cross = false;
    if (chess.red) {
        if (chess.y > 4) {
            if (dsty >= chess.y) {
                return false;
            }
        } else {
            if (dsty > chess.y) {
                return false;
            }
        }
    } else {
        if (chess.y < 5 ) {
            if (dsty <= chess.y) {
                return false;
            }
        } else {
            if (dsty < chess.y) {
                return false;
            }
        }
    }

    int sum = CalSumXY(chess,dstx,dsty);
    return (sum == 1 || sum == 10);
}

bool Widget::GoElephant(chessInfo chess, int dstx, int dsty)
{
    int sumTmp = CalSumXY(chess,dstx,dsty);
    if(sumTmp != 22)
        return false;
    int midx = (chess.x+dstx) / 2;
    int midy = (chess.y+dsty) / 2;
    for (int j=0;j < allChess;++j) {
        if (!chessInfos[j].dead&&chessInfos[j].x == midx && chessInfos[j].y == midy){
            return false;
        }
    }

    return true;
}

bool Widget::GoHousecarl(chessInfo chess, int dstx, int dsty)
{
    if (dstx < 3 || dstx > 5){
        return  false;
    }

    if(chess.red) {
        if (dsty < 7 || dsty > 9){
            return false;
        }
    } else {
        if (dsty < 0 || dsty > 2){
            return false;
        }
    }

    int sumTmp = CalSumXY(chess,dstx,dsty);
    if(sumTmp != 11)
        return false;
    return true;
}

bool Widget::GoGeneral(chessInfo chess, int dstx, int dsty)
{
    if (dstx < 3 || dstx > 6){
        return  false;
    }

    if(chess.red) {
        if (dsty < 7 || dsty > 9){
            return false;
        }
    } else {
        if (dsty < 0 || dsty > 2){
            return false;
        }
    }

    int sumTmp = CalSumXY(chess,dstx,dsty);
    if(sumTmp != 1 && sumTmp != 10)
        return false;

    // 将不能照面
    const chessInfo& king = chess.red?chessInfos[4]:chessInfos[27];
    if(king.x != dstx){
        return true;
    }

    for (auto chessTmp:chessInfos) {
        if(!chessTmp.dead&&chessInfos[4] != chessTmp && chessInfos[27] != chessTmp&& chessTmp.x == king.x){
            float div = 1.0*(chessTmp.y - chessInfos[4].y) / (chessInfos[27].y - chessInfos[4].y);
            if (div > 0 && div < 1){
                return true;
            }
        }
    }

    return false;
}

bool Widget::CheckKing(chessInfo chess, int dstx, int dsty)
{
    // 检查两将不能照面
    // 剔除自身外是否还有其他棋子在两将中间

    // 两将有照面危险
    if (chessInfos[4].x != chessInfos[27].x) {
        return true;
    }

    // 棋子未在两将中间
    if (chess.x != chessInfos[4].x){
        return true;
    }

    // 竖着走时，炮不能越过将打其他棋子
    if (dstx == chessInfos[4].x){
        return !(chess.type == cannon && m_type == general);
    }
    // 横着走检查两将中间是否有棋子
    for (auto chessTmp:chessInfos) {
        if(chess != chessTmp && chessTmp.x == chessInfos[4].x){
            float div = 1.0*(chessTmp.y - chessInfos[4].y) / (chessInfos[27].y - chessInfos[4].y);
            if (div > 0 && div < 1){
                return true;
            }
        }
    }

    return false;
}

void Widget::paintEvent(QPaintEvent *event) {
    getSuitableRect();
    drawChessBoard();
    drawChessFrom();
    drawChessKingArea();
    drawChessSoldiersArea();
    drawChesses();
}
